/***************************************
 Felipe L Amado       6797205
 Renato A V Nishimori 5121731
 *****************************************/

#include <unistd.h>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <pthread.h>
#include <assert.h>
#include <semaphore.h>
#include <signal.h>
#include <iostream>
#include "monitor.hpp"

using namespace std;

/* se UT=1000000, então nossa unidade de tempo é segundo. */
#define UT 							100000		
#define TEMPO_DO_PASSEIO			100*UT
#define PROB_DE_BILHETE_DOURADO		0.4

int capacidade;
Monitor *monitor;
sem_t *leuInfoPass;

void * novoCarro(void *argument) {
	while (1) {
		monitor->carrega();
		//INICIO DO PASSEIO
		usleep(TEMPO_DO_PASSEIO);
		//FIM DO PASSEIO
		monitor->descarrega();
	}

	return NULL;
}

void * novoPassageiro(void *argument) {

	Passageiro arg = *((Passageiro *) argument);
	sem_post(leuInfoPass);

	//CHEGADA DO PASSAGEIRO
	//printf("Novo passageiro de id %d com %d bilhete dourado\n", arg.id, arg.bilheteDourado);
	monitor->pegaCarona(arg);
	arg.vez = 1;
	monitor->pegaCarona(arg);
	
	return NULL;
}

int sorteiaBilheteDourado() {
	int x = rand()%100;
	if (x < PROB_DE_BILHETE_DOURADO*100) {
		return 1;
	}
	return 0;
}

void termina (int param) {
	cout << endl << "Encerrando o programa..." << endl;
	delete monitor;
	sem_destroy(leuInfoPass);
	exit(1);
}

int main(int argc, char **argv) {
	int numeroDeCarros;
	double taxaChegada;
	vector<pthread_t *> threadsPassageiros;
	pthread_t *threadsCarros;
	int i, *args, rc;

	srand (time(NULL));

	
	if (argc != 4) {
		printf("Uso: %s <taxaDeChegada> <capacidade> <numero de carrinhos>.\n",
				argv[0]);
		exit(-1);
	}

	taxaChegada = atof(argv[1]);
	numeroDeCarros = atoi(argv[2]);
	capacidade = atoi(argv[3]);

	sem_unlink("leuInfoPass");
    leuInfoPass = sem_open("leuInfoPass", O_CREAT, 0, 0);

	monitor = new Monitor(numeroDeCarros, capacidade);

	/* Cuidando dos sinais de terminacao */
	void (*prev_fn)(int);
	prev_fn = signal (SIGTERM,termina);
	if (prev_fn==SIG_IGN) signal (SIGTERM,SIG_IGN);
	prev_fn = signal (SIGINT,termina);
	if (prev_fn==SIG_IGN) signal (SIGINT,SIG_IGN);

	threadsCarros = (pthread_t *) malloc(numeroDeCarros * sizeof(pthread_t));
	args = (int *) malloc(numeroDeCarros * sizeof(int));
	for (i = 0; i < numeroDeCarros; i++) {
		args[i] = i;
		rc = pthread_create(&threadsCarros[i], NULL, novoCarro,
				(void *) &args[i]);
		assert (0 == rc);
	}

	Passageiro novo(-1, 0);
	while (1) {
		usleep(UT/taxaChegada);
		threadsPassageiros.push_back((pthread_t *) malloc(sizeof(pthread_t)));
		novo.id++;
		novo.bilheteDourado = sorteiaBilheteDourado();
		rc = pthread_create(threadsPassageiros.back(), NULL, novoPassageiro,
				(void *) &novo);
		assert (0 == rc);
		sem_wait(leuInfoPass);
	}

	return 0;
}
